//
//  VIPZegoVideoManager.m
//  TTProduct
//
//  Created by Taurin on 2019/12/13.
//  Copyright © 2019 TTProduct. All rights reserved.
//

#import "VIPZegoVideoManager.h"
#import "VIPZegoConfig.h"

@interface VIPZegoVideoManager() <ZegoRoomDelegate, ZegoLivePublisherDelegate,ZegoLivePlayerDelegate, ZegoSoundLevelDelegate>

@property (strong, nonatomic) VIPRTCZegoModel *rtcModel;

// SDK对象
@property (nonatomic, strong) ZegoLiveRoomApi *zegoApi;
// 音浪对象
@property (nonatomic, strong) ZegoSoundLevel *zegoSound;

// 捕捉桌面的Factory
@property (strong, nonatomic) VIPZegoVideoCaptureScreenFactory *captureFactory;

// 所有的streamID
@property (strong, nonatomic) NSMutableDictionary *streams;
// 所有辅助streamID
@property (strong, nonatomic) NSMutableArray *auxStreams;

@end

@implementation VIPZegoVideoManager

#pragma mark - Public

- (void)setupLiveServerEngine {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    // 初始化参数
    [self setupZegoConfig];
    
    [self setupZegoLog];
}

- (void)joinChannel {
    [VIPWrite writeLogWithFormat:@"%s, appId: %@, appSign:%@", __func__, self.rtcModel.appId, self.rtcModel.appSign];
    
    // 实例化ZegoAPI
    WS(weakSelf)
    [self setupZegoLiveRoomApi:self.rtcModel.appId appSign:self.rtcModel.appSign completion:^(int errorCode) {
        NSLog(@"Zego 实例化ZegoLiveRoomApi对象 errorCode : %d", errorCode);
        [VIPWrite writeLogWithFormat:@"%s, errorCode: %d", __func__, errorCode];
        if (errorCode != 0) {
            NSLog(@"ZegoAPI 初始化失败errorCode : %d", errorCode);
            return;
        }
        [weakSelf joinLiveRoom];
    }];
    
    // 实例化音浪对象
    [self setupZegoSound];
    
    // 实例化Zego共享
    [self zego_screencapture_init];
    [self screenCaptureResolution];
}

- (void)joinLiveRoom {
    [VIPWrite writeLogWithFormat:@"%s, roomID: %@", __func__, self.rtcModel.roomId];
    
    // 即将进入教室
    if (self.localWillJoin) { self.localWillJoin(self.uid); }
    
    // 加入房间
    // streamList，内部封装了 userID、userName、streamID 和 extraInfo。
    // 登录房间成功后，开发者可通过 streamList 获取到当前房间推流信息，便于后续的拉流操作。
    // 当 streamList 为空时说明当前房间没有人推流
    WS(weakSelf)
    [self.zegoApi loginRoom:self.rtcModel.roomId role:ZEGO_ANCHOR withCompletionBlock:^(int errorCode, NSArray<ZegoStream *> *streamList) {
        NSLog(@"ZegoAPI 实例化ZegoLiveRoomApi对象 errorCode : %d", errorCode);
        [VIPWrite writeLogWithFormat:@"%s, errorCode: %d", __func__, errorCode];
        if (errorCode != 0) {
            //登录房间失败
            NSLog(@"Zego 登录房间失败errorCode : %d", errorCode);
            return;
        }
        
        // 正在进入教室
        if (weakSelf.localDidJoined) { weakSelf.localDidJoined(weakSelf.uid);
        }
        
        // 开启本地预览
        [weakSelf setupZegoVideoCanvas];
        // 本地推流
        [weakSelf startPublishingLocalStream];
        // 设置当前房间推流信息
        [weakSelf setupDidLoginRoom:streamList];
    }];
}

- (void)startPublishingLocalStream {
    [VIPWrite writeLogWithFormat:@"%s, smallStream:%@, largeStream:%@", __func__, self.rtcModel.smallStream, self.rtcModel.largeStream];
    
    [self startPublishing:self.rtcModel.smallStream channelIndex:ZEGOAPI_CHN_MAIN];
}

- (void)setupDidLoginRoom:(NSArray<ZegoStream *> *)streamList {
    // 接收到内部人的流
    for (ZegoStream *stream in streamList) {
        [self setupAddInRoomStream:stream];
    }
}

- (void)setupAddInRoomStream:(ZegoStream *)stream {
    [VIPWrite writeLogWithFormat:@"%s, userID: %@, streamID:%@", __func__, stream.userID, stream.streamID];
    NSLog(@"%s, userID: %@ streamID : %@", __func__, stream.userID, stream.streamID);
    
    // 辅助流ID
    NSString *auxStreamID = kAUXStreamID(stream.userID);
    // 主流ID
    NSString *mainStreamID = kMAINStreamID(stream.userID);
    if (!self.streams[mainStreamID] && !self.streams[auxStreamID] && !self.remoteDidJoined) {
        self.remoteDidJoined(stream.userID.integerValue);
    }
    
    // 全部streamID 与 userid的映射
    self.streams[stream.streamID] = stream.userID;
    // 主流
    if ([stream.streamID hasPrefix:kMAINStreamExtraInfo]) {
        // 辅助流是否进入
        if ([self.auxStreams containsObject:auxStreamID]) {
            // 辅助流已进. 因辅助流优先, 故跳过主流.
            return;
        }
        // 辅助流未进.
    }
    
    // 辅助流
    if ([stream.streamID hasPrefix:kAUXStreamExtraInfo]) {
        [self.auxStreams addObject:stream.streamID];
        // 主流是否进入
        if (self.streams[mainStreamID]) {
            NSLog(@"接收到内部人的流 stopPlayingStream");
            // 因辅助流优先, 故跳停主流.
            [self.zegoApi stopPlayingStream:mainStreamID];
            return;
        }
        // 主流未进.
    }
    
    WS(weakSelf)
    [self remoteDidJoined:stream.userID.intValue completionHandler:^(NSView * _Nonnull remoteView) {
        [weakSelf.zegoApi startPlayingStream:stream.streamID inView:remoteView];
        [weakSelf.zegoApi setViewMode:kZegoVideoRenderMode ofStream:stream.streamID];
    }];
}

- (void)setupDeleteInRoomStream:(ZegoStream *)stream {
    [VIPWrite writeLogWithFormat:@"%s, DELETE: userID: %@, streamID: %@", __func__, stream.userID, stream.streamID];
    NSLog(@"DELETE %@ streamID : %@", stream.userID, stream.streamID);
   
    [self.streams removeObjectForKey:stream.streamID];
    // 主流退出, 代表离开房间
    if ([stream.streamID hasPrefix:kMAINStreamExtraInfo]) {
        // 辅助流ID
        NSString *streamID = kAUXStreamID(stream.userID);
        [self.auxStreams removeObject:streamID];
        // 用户离线
        if (!self.remoteDidOffline) { return; }
        self.remoteDidOffline(stream.userID.integerValue);
        return;
    }
  
    // 辅助流退出
    [self.auxStreams removeObject:stream.streamID];
    // 主流ID
    NSString *streamID = kMAINStreamID(stream.userID);
    ZegoStream *mainStream = [ZegoStream new];
    mainStream.streamID = streamID;
    mainStream.userID = stream.userID;
    mainStream.userName = stream.userName;
    
    [self setupAddInRoomStream:mainStream];
}

#pragma mark ZegoLiveRoomApi Control

// 退出房间
- (void)quitLiveVideo:(LiveQuitRoom)quitLiveVideoEvent {
    // 唯一退出房间的API
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    
    [self destroyZego];
    if (!quitLiveVideoEvent) { return; }
    quitLiveVideoEvent();
}

// 即购 没有大小流之分
- (void)setRemoteVideoStream:(NSUInteger)uid type:(VIPVideoStreamType)type {
    [VIPWrite writeLogWithFormat:@"%s, Zego nonsupport",__func__];
    [VIPWrite writeLogWithFormat:@"%s, uid: %ld, type: %ld", __func__, uid, (long)type];
}

// 本地视频采集 (打开/ 关闭)
- (void)enableLocalVideoStream:(BOOL)open {
    [VIPWrite writeLogWithFormat:@"%s, open: %d", __func__, open];
    
    [self.zegoApi enableCamera:open];
}

// 本地视频推流 (打开/ 关闭)
- (void)pushLocalVideoStream:(BOOL)muted {
    [VIPWrite writeLogWithFormat:@"%s, muted:%d", __func__, muted];
    
    [self.zegoApi muteVideoPublish:muted];
}

// 本地音频推流 (打开/ 关闭)
- (void)pushLocalAudioStream:(BOOL)muted {
    [VIPWrite writeLogWithFormat:@"%s, muted:%d", __func__, muted];
    
    [self.zegoApi muteAudioPublish:muted];
}

// 远端视频拉流个人 (打开/ 关闭)
- (void)pullRemoteVideoStream:(NSUInteger)uid muted:(BOOL)muted {
    [VIPWrite writeLogWithFormat:@"%s, uid: %ld, muted: %d", __func__, uid, muted];
    
    NSString *userID = [NSString stringWithFormat:@"%ld", uid];
    NSString *mainStreamID = kMAINStreamID(userID);
    [self.zegoApi activateAudioPlayStream:mainStreamID active:!muted];
}

// 远端音频拉流个人 (打开/ 关闭)
- (void)pullRemoteAudioStream:(NSUInteger)uid muted:(BOOL)muted {
    [VIPWrite writeLogWithFormat:@"%s, uid: %ld, muted: %d", __func__, uid, muted];
    
    NSString *userID = [NSString stringWithFormat:@"%ld", uid];
    NSString *mainStreamID = kMAINStreamID(userID);
    [self.zegoApi activateAudioPlayStream:mainStreamID active:!muted];
}

// 远端视频拉流全部 (打开/ 关闭)
- (void)pullRemoteVideoStreamAll:(BOOL)muted {
    [VIPWrite writeLogWithFormat:@"%s, muted:%d", __func__, muted];
    [VIPWrite writeLogWithFormat:@"不支持"];
    
    // 遍历所有的streamID
    NSArray *streamIDs = self.streams.allKeys;
    for (NSString *streamID in streamIDs) {
        [self.zegoApi activateAudioPlayStream:streamID active:!muted];
    }
}

// 远端音频拉流全部 (打开/ 关闭)
- (void)pullRemoteAudioStreamAll:(BOOL)muted {
    [VIPWrite writeLogWithFormat:@"%s, muted:%d", __func__, muted];
    
    [self.zegoApi enableSpeaker:!muted];
}

// 设置美颜效果选项
- (void)setBeautyEffect:(BOOL)isOpen { }

// iPhone
#if TARGET_OS_IPHONE
static bool _preposition = YES;
// 切换前置摄像头, 仅适用于 iOS 平台，不适用于 macOS
- (void)switchCamera {
    _preposition = !_preposition;
    [VIPWrite writeLogWithFormat:@"%s, preposition:%d", __func__, _preposition];
    [self.zegoApi setFrontCam:_preposition];
}
#endif

// 屏幕共享
// 全屏
- (int)sharedFullScreen {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    // 设置捕获屏幕
    zego_screencapture_set_target_screen(CGMainDisplayID());
    zego_screencapture_start_capture();
    
    [self startPublishing:self.rtcModel.largeStream channelIndex:ZEGOAPI_CHN_AUX];
    return 0;
}

// 指定窗口: 有问题
- (int)sharedScreenWindowId:(NSUInteger)windowId  {
    [VIPWrite writeLogWithFormat:@"%s, windowId:%lu", __func__, (unsigned long)windowId];
    // 设置需要捕获的窗口
//    zego_screencapture_set_target_window((ZegoWindowHandle)windowId);
//    // 启动捕获
//    zego_screencapture_start_capture();
    
    zego_screencapture_set_target_screen(CGMainDisplayID());
    zego_screencapture_start_capture();
    
    [self startPublishing:self.rtcModel.largeStream channelIndex:ZEGOAPI_CHN_AUX];
    
    return  0;
}

// 关闭屏幕共享
- (int)stopScreenCapture {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    zego_screencapture_stop_capture();
    [self.zegoApi stopPublishing:ZEGOAPI_CHN_AUX];
    return 0;
}

//- (void)switchRoleInView:(VIPVideoCanvasView *)view uid:(NSInteger)uid {
//    [VIPWrite writeLogWithFormat:@"%s, uid: %ld", __func__, (long)uid];
//    NSString *streamID = [NSString stringWithFormat:@"%ld", (long)uid];
//    self.videoCanvasDict[@(uid)] = view;
//    [self.zegoApi startPlayingStream:streamID inView:view.contentView];
//    ZegoVideoViewMode viewMode = kAgoraVideoRenderMode;
//    [self.zegoApi setViewMode:viewMode ofStream:streamID];
//}

#pragma mark - Delegate
#pragma mark ZegoRoomDelegate

// 房间内有流新增、流删除的通知,
// 在类似视频通话、直播等场景下收到房间流新增通知时拉取此新增流,
// 在收到房间流删除通知时停止拉取此删除流
- (void)onStreamUpdated:(int)type streams:(NSArray<ZegoStream *> *)streamList roomID:(NSString *)roomID {
    if (type == ZEGO_STREAM_ADD) {
        for (ZegoStream *stream in streamList) {
            [self setupAddInRoomStream:stream];
        }
        return;
    }
    
    if (type == ZEGO_STREAM_DELETE) {
        for (ZegoStream *stream in streamList) {
            [self setupDeleteInRoomStream:stream];
        }
        return;
    }
}

// 本地重新加入频道
- (void)onReconnect:(int)errorCode roomID:(NSString *)roomID {
    [VIPWrite writeLogWithFormat:@"%s, errorCode:%d, roomID:%@", __func__, errorCode, roomID];
    
    if (!self.localReJoined) { return; }
    self.localReJoined(self.uid);
}

// 用户被踢出房间
- (void)onKickOut:(int)reason roomID:(NSString *)roomID customReason:(NSString *)customReason {
    [VIPWrite writeLogWithFormat:@"%s, reason:%d, roomID:%@, customReason: %@", __func__, reason, roomID, customReason];
    if (!self.tokenDidFailure) return;
    self.tokenDidFailure();
}

#pragma mark ZegoLivePublisherDelegate

// 本地视频第一帧显示时, 触发此回调
- (void)onCaptureVideoFirstFrame:(ZegoAPIPublishChannelIndex)index {
    [VIPWrite writeLogWithFormat:@"%s, index:%lu", __func__, (unsigned long)index];
    
    // 进入教室完成
    if (!self.localFirstVideoDecoded) { return; }
    self.localFirstVideoDecoded(self.uid);
}

// 本地发布直播（推流）状态更新
- (void)onPublishStateUpdate:(int)stateCode streamID:(NSString *)streamID streamInfo:(NSDictionary<NSString *,NSArray<NSString *> *> *)info {
    [VIPWrite writeLogWithFormat:@"%s, stateCode:%d, streamID:%@", __func__, stateCode, streamID];
}

#pragma mark ZegoLivePlayerDelegate
// 远端视频渲染首帧通知
- (void)onRenderRemoteVideoFirstFrame:(NSString *)streamID {
    [VIPWrite writeLogWithFormat:@"%s, streamID:%@", __func__, streamID];
    
    if (!self.remoteFirstVideoDecoded) { return; }
    
    NSUInteger uid = [self.streams[streamID] integerValue];
    // 远端 视频渲染后 可以在这里处理
    // 只是通知老师 告诉自己进入房间了
    self.remoteFirstVideoDecoded(uid);
}

// 远端用户停止/重新发送视频回调
- (void)onRemoteCameraStatusUpdate:(int)status ofStream:(NSString *)streamID reason:(int)reason {
    [VIPWrite writeLogWithFormat:@"%s, status:%d, streamID:%@, reason:%d", __func__, status, streamID, reason];
    
    if (!self.didVideoMuted) return;
    
    NSUInteger uid = [self.streams[streamID] integerValue];
    bool muted = status == ZEGOAPI_DEVICE_CLOSE;
    
    self.didVideoMuted(muted, uid);
}

// 远端麦克风状态通知
- (void)onRemoteMicStatusUpdate:(int)status ofStream:(NSString *)streamID reason:(int)reason {
    [VIPWrite writeLogWithFormat:@"%s, status:%d, streamID:%@, reason: %d", __func__, status, streamID, reason];
    
    if (!self.didAudioMuted) return;
    
    NSUInteger uid = [self.streams[streamID] integerValue];
    bool muted = status == ZEGOAPI_DEVICE_CLOSE;
    self.didAudioMuted(muted, uid);
}

// 自己推流的质量
- (void)onPublishQualityUpdate:(int)quality stream:(NSString *)streamID videoFPS:(double)fps videoBitrate:(double)kbs {
    NSUInteger uid = self.uid;
    [self qualityUpdate:quality uid:uid videoBitrate:kbs];
}

// 拉流质量
- (void)onPlayQualityUpdate:(int)quality stream:(NSString *)streamID videoFPS:(double)fps videoBitrate:(double)kbs {
    if (!self.videoNetworkQuality) { return; }
    
    NSUInteger uid = [self.streams[streamID] integerValue];
    
    [self qualityUpdate:quality uid:uid videoBitrate:kbs];
}

- (void)qualityUpdate:(int)quality uid:(NSUInteger)uid videoBitrate:(double)kbs {
    // 没网
    NSInteger level = kbs == 0 ? 4 : quality;
    self.videoNetworkQuality(uid, level);
}

// 调用 [ZegoLiveRoomApi (Player) -startPlayingStream:inView:] 或 [ZegoLiveRoomApi (Player) -startPlayingStream:inView:params:] 拉流成功后，会收到此回调通知
- (void)onPlayStateUpdate:(int)stateCode streamID:(NSString *)streamID {
    [VIPWrite writeLogWithFormat:@"%s, stateCode:%d, streamID:%@", __func__, stateCode, streamID];
}

#pragma mark ZegoSoundLevelDelegate

// 采集音量提示回调
- (void)onCaptureSoundLevelUpdate:(ZegoSoundLevelInfo *)captureSoundLevel {
    if (!self.audioVolumeIndication) { return; }
    NSUInteger volume = captureSoundLevel.soundLevel * 2.55;
    NSUInteger uid = [self.streams[captureSoundLevel.streamID] integerValue];
    self.audioVolumeIndication(uid, volume);
}

// 播放音量回调（展示谁在说话)
- (void)onSoundLevelUpdate:(NSArray<ZegoSoundLevelInfo *> *)soundLevels {
    if (!self.audioVolumeIndication) { return; }
    for (int i = 0; i < soundLevels.count; i++) {
        ZegoSoundLevelInfo *volumeInfo = soundLevels[i];
        NSUInteger uid = [self.streams[volumeInfo.streamID] integerValue];
        
        NSUInteger volume = volumeInfo.soundLevel * 2.55;
        self.audioVolumeIndication(uid, volume);
    }
}

#pragma mark - libZegoScreenCaptureOSX

// 数据采集的回调
void frame_available_notify2(void *data, uint32_t length, const struct ZegoScreenCaptureVideoCaptureFormat *video_frame_format, uint64_t reference_time, uint32_t reference_time_scale, void *user_data) {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    
    CMTime pts= CMTimeMake(reference_time, reference_time_scale);
    VIPZegoVideoCaptureScreenFactory *captureFactory = [VIPZegoVideoManager shareManager].captureFactory;
    if (captureFactory.screenDevice.isCapturing) {
        [captureFactory.screenDevice captureOutputPixelBuffer:data timeStamp:pts];
    }
}

// 采集错误的回调
void zego_screencapture_capture_error_notify2(enum ZegoScreenCaptureCaptureError error, void *data) {
    [VIPWrite writeLogWithFormat:@"%s, error: %d", __func__, error];
    if (error == kCaptureErrorNotify) {
        NSAlert *alert = [[NSAlert alloc] init];
        alert.messageText = @"采集异常";
        alert.informativeText = @"当前窗口无法共享，请检查权限并且将窗口置顶";
        [alert runModal];
    }
}

#pragma mark - Private

- (void)startPublishing:(NSString *)streamID channelIndex:(int)index {
    [VIPWrite writeLogWithFormat:@"%s, streamID: %@, index:%d", __func__, streamID, index];
    
    // 设置推流
    [self.zegoApi startPublishing2:streamID title:nil flag:kZegoPublishFlag extraInfo:nil params:nil channelIndex:index];
}

#pragma mark Setup ZegoAPI

// 初始化Zego属性
- (void)setupZegoConfig {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    _streams = nil;
    _auxStreams = nil;
    
    NSString *localUID = [NSString stringWithFormat:@"%ld", self.uid];
    self.streams[self.rtcModel.smallStream] = localUID;
    self.streams[self.rtcModel.largeStream] = localUID;
    
    // 是否启用测试环境
#ifdef DEBUG
    [ZegoLiveRoomApi setUseTestEnv:YES];
#else
    [ZegoLiveRoomApi setUseTestEnv:NO];
#endif
    // 设置用户 ID 及用户名
    NSString *uid = [NSString stringWithFormat:@"%ld", self.uid];
    [ZegoLiveRoomApi setUserID:uid userName:uid];
    
    // 设置外部采集
    [ZegoExternalVideoCapture setVideoCaptureFactory:self.captureFactory channelIndex:ZEGOAPI_CHN_AUX];
    
    // 设置业务类型: 0: 直播类型, 2: 实时音视频类型. 默认为:0
    [ZegoLiveRoomApi setBusinessType:kZegoBusinessType];
}

- (void)setupZegoLog {
    // 设置日志等级
    zego_screencapture_set_log_level(kZegoScreenCaptureLogLevel, kZegoLogPath);
}

// 初始化SDK对象
- (void)setupZegoLiveRoomApi:(NSString *)appId appSign:(NSString *)appSign completion:(ZegoInitSDKCompletionBlock)completion {
    [VIPWrite writeLogWithFormat:@"%s, appId:%@, appSign:%@", __func__, appId, appSign];
    // 实例化Zego
    NSData *stringToSign = [appSign tt_toSignString];
    [VIPWrite writeLogWithFormat:@"%s, stringToSign:%@", __func__, stringToSign];
    
    // 初始化SDK对象
    _zegoApi = [[ZegoLiveRoomApi alloc] initWithAppID:appId.intValue appSignature:stringToSign completionBlock:completion];
    // 房间内部事件回调
    [_zegoApi setRoomDelegate:self];
    // 推流回调
    [_zegoApi setPublisherDelegate:self];
    // 拉流回调
    [_zegoApi setPlayerDelegate:self];
    
    [self setupVideoCaptureResolution:kZegoMainVideoResolution bitrate:kZegoMainVideoBitrate index:ZEGOAPI_CHN_MAIN];
    [self setupVideoCaptureResolution:kZegoAuxVideoResolution bitrate:kZegoAuxVideoBitrate index:ZEGOAPI_CHN_AUX];
}

// 设置视频配置
- (void)setupVideoCaptureResolution:(CGSize)resolution bitrate:(int)bitrate index:(ZegoAPIPublishChannelIndex)index {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    ZegoAVConfig *config = [ZegoAVConfig new];
    // 帧率
    config.fps = kZegoVideoFPS;
    // 分辨率
    config.videoCaptureResolution = resolution;
    config.videoEncodeResolution = config.videoCaptureResolution;
    // 比特率(码率)
    config.bitrate = bitrate;
    [self.zegoApi setAVConfig:config channelIndex:index];
}

// 初始化本地画布
- (void)setupZegoVideoCanvas {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    
    // 设置本地预览模式
    [self.zegoApi setPreviewViewMode:kZegoVideoRenderMode];
    
    // 设置本地预览视图
    [self.zegoApi setPreviewView:self.localView channelIndex:ZEGOAPI_CHN_MAIN];
    // 开启预览
    [self.zegoApi startPreview:ZEGOAPI_CHN_MAIN];
}

// 初始化音浪对象
- (void)setupZegoSound {
    _zegoSound = [ZegoSoundLevel sharedInstance];
    // 声音回调
    [_zegoSound setSoundLevelDelegate:self];
    [_zegoSound startSoundLevelMonitor];
}

#pragma mark Setup ScreenCapture

// 初始化外部采集
- (void)zego_screencapture_init {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    
    // 设置捕获错误回调
    zego_screencapture_reg_capture_error_notify(zego_screencapture_capture_error_notify2 , NULL);
    
    // 设置捕获数据回调
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types"
    zego_screencapture_reg_captured_frame_available_notify(frame_available_notify2, NULL);
#pragma clang diagnostic pop
    // 初始化
    zego_screencapture_init();
}

// 设置外部采集属性
- (void)screenCaptureResolution {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    // 设置桌面分享的采集帧率，即OnCapturedFrameAvailable每秒回调次数
    zego_screencapture_set_fps(kZegoVideoFPS);
    
    // 设置是否同时捕捉光标, 非0显示
    zego_screencapture_set_cursor_visible(1);
    
    // 设置是否在捕捉到分享画面的同时显示点击动画, 非0值显示鼠标点击动画
    zego_screencapture_enable_click_animation(1);
    
    // 设置外部采集的格式
    zego_screencapture_set_capture_video_pixel_format(kZegoVideoPixelFormat);
}

#pragma mark Setup property

- (NSMutableDictionary *)streams {
    if (!_streams) {
        _streams = [NSMutableDictionary dictionary];
    }
    return _streams;
}

- (NSMutableArray *)auxStreams {
    if (!_auxStreams) {
        _auxStreams = [NSMutableArray array];
    }
    return _auxStreams;
}

- (VIPZegoVideoCaptureScreenFactory *)captureFactory {
    if (!_captureFactory) {
        _captureFactory = [VIPZegoVideoCaptureScreenFactory new];
    }
    return _captureFactory;
}

- (VIPRTCZegoModel *)rtcModel {
    if (!_rtcModel) {
        _rtcModel = (VIPRTCZegoModel *)self.rtcModel;
    }
    return _rtcModel;
}

#pragma mark - Destroy Zego

- (void)destroyZego {
    [VIPWrite writeLogWithFormat:@"%s", __func__];
    
    // 停止推流、停止共享
    [self stopScreenCapture];
    [self.zegoApi stopPublishing:ZEGOAPI_CHN_MAIN];
    
    [self.zegoApi logoutRoom]; // 退出房间
    
    _zegoApi = nil; // 断开引用 ZegoLiveRoomApi 实例
    _rtcModel = nil; // 销毁 rct 数据
}

static VIPZegoVideoManager* _instance = nil;
+ (instancetype)shareManager {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init];
    });
    return _instance ;
}

+ (id)allocWithZone:(struct _NSZone *)zone {
    return [VIPZegoVideoManager shareManager];
}

- (id)copyWithZone:(struct _NSZone *)zone {
    return [VIPZegoVideoManager shareManager];
}

@end
